#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../getString/getString.h"
#include "../Parser/parser.h"
#include "../Tag/Tag.h"
#include "tdc.h"



void TDC_Configuracion(TDC* tdc, tipoTag vec_tags[],int* cant_vec_tags){
  int i;
  tdc->canttags=*cant_vec_tags;
  for (i=0;i<*cant_vec_tags;i++){
    set_tag(&(tdc->vectorTag[i]), vec_tags[i].tag);
    set_subtags(&(tdc->vectorTag[i]), vec_tags[i].subtags, vec_tags[i].cant_subtags);
  }
}

int TDC_Crear(TDC* tdc, char* archconfig, char* archSalida){

	tdc->archprograma= fopen(archSalida, "wt");
  printf("archSalida: %s\n",archSalida);
  if (tdc->archprograma==NULL){
    fprintf(stderr,"El archivo para la documentacion no se pudo crear\n" );
    return -1;
  }

  int cant_vec_tags = 0;
  if (archconfig!=NULL){
    printf("Carga configuracion desde archivo\n");
    Cargar_tag_ArchConf (tdc->vectorTag,&cant_vec_tags,archconfig);
    tdc->canttags=cant_vec_tags;
  }
  return OK;
  }


void quitar_linea (char** buffer ,int* cant_pos, int pos_actual){
  char** buffer2=(char**)malloc(sizeof(char*)*(*cant_pos-1));
  int i;
  for (i=0;i<pos_actual;i++){
    buffer2[i]=(char*)malloc(sizeof(char)*(strlen(buffer[i])+1));
    buffer2[i]=strdup(buffer[i]);
  }
  for (i=pos_actual+1;i<*cant_pos;i++){
    buffer2[i-1]=(char*)malloc(sizeof(char)*(strlen(buffer[i])+1));
    buffer2[i-1]=strdup(buffer[i]);
  }
  //Libero el buffer>>>>>>>>>>>>>>>>>>>>>>>>>>>
  for(i=0;i<*cant_pos;i++)
    free(buffer[i]);
  free(buffer);
  //Libero el buffer<<<<<<<<<<<<<<<<<<<<<<<<<<<

  (*cant_pos)--;
  buffer=(char**)malloc(sizeof(char*)*(*cant_pos));
  for (i=0;i<*cant_pos;i++){
    buffer[i]=(char*)malloc(sizeof(char)*(strlen(buffer2[i])+1));
    buffer[i]=strdup(buffer2[i]);
  }

  //Libero el buffer2>>>>>>>>>>>>>>>>>>>>>>>>>>
  for(i=0;i<*cant_pos;i++)
    free(buffer2[i]);
  free(buffer2);
  //Libero el buffer2<<<<<<<<<<<<<<<<<<<<<<<<<<
}

int condicion_0 (char** buffer ,int cant_pos){

  Parametros lista_parametros;
  Parser parser;
  lista_parametros.vec_parametros=NULL;
  lista_parametros.cant=0;
  agregar_parametro(&lista_parametros,"/**");
  agregar_parametro(&lista_parametros,"*/");
  parser_New(&parser, &lista_parametros);
  Parsear(&parser,buffer[0]);
  int i;
  char** tokens;

  carga_tokens(parser,&tokens);
  for (i=0;i<tokensMax(parser);i++){
    if (!strcmp(tokens[i],"*/")){
      limpiar_lista_tokens(tokens, tokensMax(parser));
      limpiar_lista_parametros(&lista_parametros);
      parser_Destruir(&parser);
      fprintf(stderr,"Error: comentario AUTO monolinea\n");
      return 1;
    }
  }
  limpiar_lista_tokens(tokens, tokensMax(parser));
  limpiar_lista_parametros(&lista_parametros);
  parser_Destruir(&parser);
  return OK;
}

/*se fija si el "/**" aparece en alguna otra posicion ademas de la primera */
int condicion_1 (char** buffer ,int cant_pos   ){
  //variables>>
  int a,i,j,flag;
  Parametros lista_parametros;
  Parser parser;
  int cant_tokens;

  //>>
  flag=0;
  lista_parametros.vec_parametros=NULL;
  lista_parametros.cant=0;

  a=agregar_parametro(&lista_parametros, "/**");


  for (i=1;i<cant_pos;i++ ){
    a=parser_New(&parser, &lista_parametros);
    a=Parsear (&parser, buffer[ i ]);
    cant_tokens=tokensMax ( parser );// cargo la cantidad de tokens
    for (j=0; j<cant_tokens; j++){//**
        if (strstr(parser.tokens[ j ],"/**")!=NULL ){
            flag++;
        }
    }//**
    a=parser_Destruir(& parser);
  }
  a=limpiar_lista_parametros(&lista_parametros);

  if (flag==0)
    return 0;
  else{
    fprintf(stderr,"Error: el tag (/**) fue encontrado en mas una ocasion dentro del comentario AUTO\n");
    return -1;
  }
}

/*Se fija si la primer linea del Buffer contiene al Tag principal y si éste se encuentra en la posicion inicial
Si el taga esta en la posicion inicial devuelve 0 sino 2
*/
int condicion_2(char** buffer, int cant_pos, tipoTag tags[], int cant_tags ){

  int a,i,j,m,k,flag;
  Parametros lista_parametros;
  Parser parser;
  char** tokens;
  char* temp;
  int cant_tokens;
  flag=0;
  Crear_lista_parametros (&lista_parametros);

  char* aux;
  for (i=0;i<cant_tags;i++){
    aux=(char*)malloc(sizeof(char*)*(strlen(tags[i].tag)+2));//uno para el "\0" y otro para el "@".
    strcpy(aux,"@");
    strcat(aux,tags[i].tag);
    a=agregar_parametro(&lista_parametros,aux );
    free(aux);
  }
  a=parser_New(&parser, &lista_parametros);
  a=Parsear (&parser, buffer[1]);
  carga_tokens( parser, & tokens  );
  cant_tokens=tokensMax ( parser );
  for (j=0; j<cant_tokens; j++){
    for (k=0;k<cant_tags;k++){
      aux=(char*)malloc(sizeof(char*)*(strlen(tags[k].tag)+2));//uno para el "\0" y otro para el "@".
      strcpy(aux,"@");
      strcat(aux,tags[k].tag);
      if (strstr(tokens[ j ],aux)){
        flag++;
        temp=(char*)malloc(sizeof(char)*(strlen(aux)+1));
        temp=strdup(aux);
      }
      free(aux);
    }
  }
  a=parser_Destruir(& parser);
  for (m=0; m<cant_tokens;m++)
      free (tokens[m] );
  free(tokens);
  a=limpiar_lista_parametros(&lista_parametros);

  if (flag==1){
    buffer[1]=(char*)realloc(buffer[1],sizeof(char)*(strlen(temp)+1) );
    buffer[1]=strdup(temp);
    free(temp);
    return 0;
  }else{
    fprintf(stderr,"Error: el Tag principal no fue hallado en la primer linea del comentario AUTO\n");
    return -1;
  }
}


/*Esta condicion verifica que no hay 2 o mas tags en un mismo comentario, y que hay por lo menos 1*/
int condicion_3(char** buffer, int cant_pos, tipoTag tags[], int cant_tags ){

  int a,i,j,m,k,flag;
  Parametros lista_parametros;
  Parser parser;
  char** tokens;
  int cant_tokens;
  flag=0;
  Crear_lista_parametros (&lista_parametros);

  char* aux;
  for (i=0;i<cant_tags;i++){
    aux=(char*)malloc(sizeof(char*)*(strlen(tags[i].tag)+2));//uno para el "\0" y otro para el "@".
    strcpy(aux,"@");
    strcat(aux,tags[i].tag);
    a=agregar_parametro(&lista_parametros,aux );
    free(aux);
  }

  for (i=1;i<cant_pos; i++ ){//>>>
    a=parser_New(&parser, &lista_parametros);
    a=Parsear (&parser, buffer[ i ]);
    carga_tokens( parser, & tokens  );
    cant_tokens=tokensMax ( parser );
    for (j=0; j<cant_tokens; j++){
      for (k=0;k<cant_tags;k++){
        aux=(char*)malloc(sizeof(char*)*(strlen(tags[k].tag)+2));//uno para el "\0" y otro para el "@".
        strcpy(aux,"@");
        strcat(aux,tags[k].tag);
        if (strstr(tokens[ j ],aux))
           flag++;
        free(aux);
      }
    }
    a=parser_Destruir(& parser);
    for (m=0; m<cant_tokens;m++)
        free (tokens[m] );
    free(tokens);
  }//>>>>
  a=limpiar_lista_parametros(&lista_parametros);

  if (flag==1)
    return 0;
  else{
    fprintf(stderr,"Error: fueron hallados mas de un Tag principal en el comentario AUTO\n");
    return -1;
  }
}

/*Verifica que no haya renglones en blanco en un comentario AUTO*/
/*A esta verificacion se le podria pasar un parametro int* que indique en que lineas fallo para que no sean copiadas
y que de esta manera el comentario no se pierda (poniendo como limite 5 renglones en blanco)
*/
int condicion_4(char** buffer, int* cant_pos ){
  int i;
  for (i=0; i<*cant_pos; i++)
    if (!strcmp(buffer[ i ],"")){
    quitar_linea (buffer ,cant_pos,i);
    fprintf(stderr,"Advertencia: una linea en blanco dentro del comentario AUTO fue eliminada\n");
    }
    return OK;
}

/*Condiciones del param
1° todos los param tienen que estar seguidos
2° Controla si @param viene con el delimitador " : " para que entonces  otra funcion se encargue de
 "@param void", y si hay más de un param entonces se pondra param ...


delimitador codigos
1°  0 entonces los parametros se copian tal cual los encuentra,
2°  1 entonces se tiene que imprimir @param void
3°  2 entonces se tiene que imprimir @param ...

*/
int condicion_5(char** buffer,int cant_pos){

  int i,continuar,flag;
  if (strstr(buffer[1],"@function")){
    i=2;
    continuar=0;
    flag=0;
    while((i<cant_pos)&&(!continuar)){ //Busca el primer @param.
      if (strstr(buffer[i],"@param")){
        continuar++;
        flag++;
      }
      i++;
    }
    continuar=0;
    while((i<cant_pos)&&(!continuar)){ //cuenta los @param que esten seguidos.
      if (!strstr(buffer[i],"@param")){
        continuar++;
      }
      i++;
    }
    continuar=0;
    while((i<cant_pos)&&(!continuar)){ //Busca si hay otro @param.
      if (strstr(buffer[i],"@param")){
        continuar++;
        flag++;
      }
      i++;
    }
    if (flag==1)
      return OK;
    else{
      fprintf(stderr,"Error: el subtag param no se encontro correctamente ordenado\n");
      return -1;
    }
  }
  return OK;
}

/*
Controla que los subtags esten anidados al tag principal
*/
int condicion_6 (char** buffer, int cant_pos, tipoTag tags[], int cant_tags ){
  int i, flag,tagindex,cant_tokens,index,continuar;
  char** tokens;
  Parametros lista_parametros;
  Parser parser;
  Crear_lista_parametros(&lista_parametros);
  agregar_parametro(&lista_parametros,"@");
  agregar_parametro(&lista_parametros," ");
  parser_New(&parser,&lista_parametros);


  //Busca el tag>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  Parsear(&parser,buffer[1]);
  carga_tokens(parser,&tokens);
  cant_tokens=tokensMax(parser);
  index=0;
  continuar=0;
  while (!continuar){
    if (!strcmp(tokens[index],"@"))
      continuar++;
    index++;
  }
  buscar_tags(tags, cant_tags, tokens[index], &tagindex);
  limpiar_lista_tokens(tokens,cant_tokens);
  //Busca el tag<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

  i=2;
  flag=0;
  while ((i<cant_pos-1)&&(!flag)){  //se arranca desde la tercer linea del buffer y se recorre hasta una antes de la ultima.
    Parsear(&parser,buffer[i]);
    carga_tokens(parser,&tokens);
    cant_tokens=tokensMax(parser);
    index=0;
    continuar=0;
    while (!continuar){
      if (!strcmp(tokens[index],"@"))
        continuar++;
      index++;
    }
    if (buscar_subtags(&tags[tagindex], tokens[index])!=OK){
      flag++;
    }
    limpiar_lista_tokens(tokens,cant_tokens);
    i++;
  }
  limpiar_lista_parametros(&lista_parametros);
  parser_Destruir(&parser);


  if (flag==0)
    return OK;
  else{
    fprintf(stderr,"Error: fue hallado un subtag que no se encontraba anidado al Tag principal\n");
    return -1;
  }
}


int condiciones (char** buffer, int*   cant_pos , tipoTag tags[], int cant_tags){
  int exeCod=0;
  exeCod= condicion_0(buffer, *cant_pos);
  if ( exeCod==0) exeCod= condicion_1(buffer, *cant_pos);
  if ( exeCod==0) exeCod= condicion_2(buffer, *cant_pos, tags, cant_tags);
  if ( exeCod==0) exeCod= condicion_3(buffer, *cant_pos, tags, cant_tags);
  if ( exeCod==0) exeCod= condicion_4(buffer, cant_pos);
  if ( exeCod==0) exeCod= condicion_5(buffer, *cant_pos);
  if ( exeCod==0) exeCod= condicion_6(buffer, *cant_pos, tags, cant_tags);
  return exeCod;
}



int TDC_Documentar(TDC* tdc, char* pruebas) {
  int error;
  int cant_tags=tdc->canttags;
  tipoTag* tags;
  tags = tdc->vectorTag;

  int continuar=0;
  int i;
  int cant_linea;
  FILE* puntarchprograma;
  char* linea= NULL;
  char** buffer=(char**)malloc(sizeof(char*));

  Parametros lista_parametros;
  Parser parser;
  lista_parametros.vec_parametros=NULL;
  lista_parametros.cant=0;
  agregar_parametro(&lista_parametros,"/**");
  agregar_parametro(&lista_parametros,"*/");
  parser_New(&parser, &lista_parametros);

  puntarchprograma = fopen(pruebas,"rt");

  cant_linea=0;
  getString(&linea, puntarchprograma);
  while (!feof(puntarchprograma))  {
    if (strstr(linea,"/**")!=NULL){
      cant_linea++;
      buffer=(char**)realloc(buffer,sizeof(char*)*(cant_linea));
      buffer[cant_linea-1]=(char*)malloc(sizeof(char)*(strlen(linea)+1));
      strcpy(buffer[cant_linea-1],linea);
      continuar=1;
    }
    if (continuar!=0){
      continuar=0;
      //Modificando la creacion del buffer>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      Parsear(&parser,linea);
      char** tokens;
      carga_tokens(parser,&tokens);
      for (i=0;i<tokensMax(parser);i++){
        if (!strcmp(tokens[i],"*/")){
          continuar=1;
        }
      }
      limpiar_lista_tokens(tokens, tokensMax(parser));
      //Modificando la creacion del buffer<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
      while ((!continuar)&&(!feof(puntarchprograma))){
        getString(&linea, puntarchprograma);
        //printf("Linea leida: '%s'\n",linea);
        cant_linea++;
        buffer=(char**)realloc(buffer,sizeof(char*)*(cant_linea));
        buffer[cant_linea-1]=(char*)malloc(sizeof(char)*(strlen(linea)+1));
        strcpy(buffer[cant_linea-1],linea);
        if (strstr(linea,"*/")!=NULL){
          continuar=1;
        }
      }
    }
    if(cant_linea!=0){
      error=condiciones ( buffer,  &cant_linea, tags, cant_tags);
      if (error==0){
       // printf("------------se puede usar, termino OK---------------\n");
        fprintf(tdc->archprograma,"/**\n");
        for (i=1;i<(cant_linea-1);i++){
          fprintf(tdc->archprograma,"%s\n",buffer[i]);
        }
        fprintf(tdc->archprograma,"*/\n");
        fprintf(tdc->archprograma,"\n\n");
      }
    }
    //libero BUFFER y lo dejo listo para volver a ser usado>>>>>>
    for(i=0;i<cant_linea;i++)
      free(buffer[i]);
    free(buffer);
    buffer=(char**)malloc(sizeof(char*));
    cant_linea=0;
    //libero BUFFER y lo dejo listo para volver a ser usado<<<<<<
    continuar=0;
    getString(&linea, puntarchprograma);
  }

  fclose(puntarchprograma);
  free(buffer);
  limpiar_lista_parametros(&lista_parametros);
  parser_Destruir(&parser);
  return OK;
}

int TDC_Cerrar(TDC* tdc) {
  fclose(tdc->archprograma);
//  free(tdc);
  int exeStatus = 0;

  return exeStatus;
}



